#include <leveldb/db.h>

#include <stdexcept>
#include <iostream>

#include <protocol/TBinaryProtocol.h>
#include <transport/TBufferTransports.h>

#include "thrift/CrawlerServer.h"

using namespace std;
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using boost::shared_ptr;
using namespace crawler::server;

int main(int argc, char **argv)
{
  string db_path = argv[1];
  leveldb::Options options;
  options.create_if_missing = true;
	options.write_buffer_size = 256 * 1048576;
  leveldb::DB *db;
  leveldb::Status status = leveldb::DB::Open(options, db_path, &db);
  if (!status.ok()) {
    cout << "Failed to open leveldb, path=" + db_path
                              + " error=" + status.ToString() << endl;
  }

  leveldb::Iterator* iter = db->NewIterator(leveldb::ReadOptions());
  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
    Page page;
    shared_ptr<TMemoryBuffer> mem_buf(new TMemoryBuffer);
    shared_ptr<TBinaryProtocol> bin_proto(new TBinaryProtocol(mem_buf));
    mem_buf->resetBuffer((uint8_t*)iter->value().data(), iter->value().size());
    page.read(bin_proto.get());

    if (page.url.find("javascript") != string::npos) {
      cout << "delete " << page.url << endl;
      status = db->Delete(leveldb::WriteOptions(), page.url);
      if (!status.ok()) {
        cout << "Failed to delete key from leveldb, key=" +page.url 
                 + " error=" + status.ToString() << endl;
      }
    }

    if (page.content.find("Skip this ad") != string::npos) {
      cout << "reset page " << page.url << endl;
      page.__set_status(PageStatus::kNotYetDownload);

      shared_ptr<TMemoryBuffer> mem_buf(new TMemoryBuffer);
      shared_ptr<TBinaryProtocol> bin_proto(new TBinaryProtocol(mem_buf));
      mem_buf->resetBuffer();
      page.write(bin_proto.get());
      uint8_t* buf_ptr;
      uint32_t sz;
      mem_buf->getBuffer(&buf_ptr, &sz);

      leveldb::Slice value(reinterpret_cast<const char*>(buf_ptr), sz);
      status = db->Put(leveldb::WriteOptions(), page.url, value);
      if (!status.ok()) {
        throw std::runtime_error("Failed to insert into leveldb, key=" + page.url +
                                 "error=" + status.ToString());
      }
    }
  }

  return 0;
}

